import { getMetadata } from '@/api/iot/device'
import { getUnits } from '@/api/iot/product'
import { formatDate } from '@/utils/dateUtils'

/**
 * 物模型数据格式化
 */
export class DataType {

  static #metadataMap = new Map()
  static #unitMap = new Map()

  /**
   * 对值进行格式化
   * @param valueType 物模型数据类型
   * @param value 值
   */
  static async format(valueType, value) {
    if (!valueType) {
      return value
    }

    if (!this.#unitMap.size) {
      await getUnits()
        .then(({ data = [] }) => data.forEach(unit => this.#unitMap.set(unit.id, unit.symbol)))
    }

    if (valueType.type === 'int' || valueType.type === 'long') {
      let val = Number(value)
      if (!Number.isNaN(val)) {
        const unit = this.#unitMap.get(valueType.unit) || ''
        return Math.floor(val) + unit
      }
      return value
    }

    if (valueType.type === 'float' || valueType.type === 'double') {
      let val = Number(value)
      if (!Number.isNaN(val)) {
        const unit = this.#unitMap.get(valueType.unit) || ''
        return val.toFixed(valueType.scale) + unit
      }
      return value
    }

    if (valueType.type === 'boolean') {
      if (value === valueType.trueValue) {
        return valueType.trueText
      }
      if (value === valueType.falseValue) {
        return valueType.falseText
      }
      return value
    }

    if (valueType.type === 'string') {
      return value
    }

    if (valueType.type === 'enum') {
      const element = valueType.elements.find(element => value === element.value)
      if (element) {
        return element.text
      }
      return value
    }

    if (valueType.type === 'date') {
      const dateFormat = valueType.format
      return formatDate(value, dateFormat)
    }

    if (valueType.type === 'array') {
      if (Array.isArray(value)) {
        let values = []
        for (let val of value) {
          await this.format(valueType.elementType, val).then(result => values.push(result))
        }
        return values
      }
      return value
    }

    if (valueType.type === 'object') {
      if (Array.isArray(valueType.properties)) {
        let values
        if (Array.isArray(value)) {
          values = []
          for (let i = 0; i < valueType.properties.length; i++) {
            await this.format(valueType.properties[i].valueType, value[i]).then(result => values.push(result))
          }
        } else {
          values = {}
          for (let property of valueType.properties) {
            if (value.hasOwnProperty(property.id)) {
              await this.format(property.valueType, value[property.id]).then(result => values[property.id] = result)
            }
          }

          if (valueType.properties.length === 1 && !value.hasOwnProperty(valueType.properties[0].id)) {
            await this.format(valueType.properties[0].valueType, value).then(result => values = result)
          }

        }
        return values
      }
      return value
    }

    if (valueType.type === 'geoPoint') {
      if (Array.isArray(value)) {
        return value.join()
      } else if (value.lon && value.lat) {
        return [value.lon, value.lat].join()
      } else {
        return value
      }
    }
  }

  /**
   * 对属性值进行格式化
   * @param deviceId 设备id
   * @param propertyId 属性id
   * @param value 值
   */
  static async formatPropertyValue(deviceId, propertyId, value) {
    let valueType;
    await this.#getValueType(deviceId, propertyId, 'properties').then(data => valueType = data)
    return this.format(valueType, value)
  }

  /**
   * 对功能值进行格式化
   * @param deviceId 设备id
   * @param functionId 功能id
   * @param value 值
   */
  static async formatFunctionValue(deviceId, functionId, value) {
    let valueType;
    await this.#getValueType(deviceId, functionId, 'functions').then(data => valueType = data)
    return this.format(valueType, value)
  }

  /**
   * 对事件值进行格式化
   * @param deviceId 设备id
   * @param eventId 事件id
   * @param value 值
   */
  static async formatEventValue(deviceId, eventId, value) {
    let valueType;
    await this.#getValueType(deviceId, eventId, 'events').then(data => valueType = data)
    return this.format(valueType, value)
  }

  /**
   * 对标签值进行格式化
   * @param deviceId 设备id
   * @param tagId 标签id
   * @param value 值
   */
  static async formatTagValue(deviceId, tagId, value) {
    let valueType;
    await this.#getValueType(deviceId, tagId, 'tags').then(data => valueType = data)
    return this.format(valueType, value)
  }

  /**
   * 获取模型值类型
   * @param deviceId 设备id
   * @param propertyId 模型id
   * @param type 模型类型（functions、events、tags）
   */
  static async #getValueType(deviceId, propertyId, type) {
    let metadata = this.#metadataMap.get(deviceId)
    if (!metadata) {
      await getMetadata(deviceId).then(({ data }) => {
        this.#metadataMap.set(deviceId, data)
        metadata = data
      })
    }

    if (!metadata) {
      return
    }

    const data = metadata[type]
    if (!data) {
      return
    }
    let valueType = 'valueType'
    if (type === 'functions') {
      valueType = 'output'
    }

    return data[valueType]
  }

}
